package crypto

import (
	"encoding/hex"
	"math/big"

	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"

	"golang.org/x/crypto/poly1305"
)

func NewMac() *mac {
	key, err := hex.DecodeString("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20")
	if err != nil {
		panic(err)
	}

	var key2 [32]byte
	copy(key2[:], key[:32])

	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	// seed := make([]byte, ed25519.SeedSize)
	// _, err := io.ReadFull(rand.Reader, seed)
	// if err != nil {
	// 	panic(err)
	// }
	//
	// privateKey := ed25519.NewKeyFromSeed(seed)
	// publicKey := make([]byte, ed25519.PublicKeySize)
	// copy(publicKey, privateKey[32:])

	// elliptic.P224()
	// elliptic.P256()
	// elliptic.P384()
	// elliptic.P521()
	// elliptic.Marshal()
	// elliptic.Unmarshal()
	// elliptic.MarshalCompressed()
	// elliptic.UnmarshalCompressed()
	// ellipticPrivateKey, x, y err := elliptic.GenerateKey(elliptic.P256(), rand.Reader)

	ecdsaPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		panic(err)
	}

	data := &mac{
		key:             key,
		key2:            &key2,
		publicKey:       publicKey,
		privateKey:      privateKey,
		ecdsaPrivateKey: ecdsaPrivateKey,
		b:               nil,
	}

	return data
}

type mac struct {
	key             []byte
	key2            *[32]byte
	publicKey       ed25519.PublicKey
	privateKey      ed25519.PrivateKey
	ecdsaPrivateKey *ecdsa.PrivateKey
	b               []byte
}

func (r *mac) Key(key []byte) *mac {
	r.key = key

	return r
}
func (r *mac) Key2(key2 *[32]byte) *mac {
	r.key2 = key2

	return r
}

// Hmac
// key
// b
func (r *mac) Hmac(source []byte) []byte {
	mac := hmac.New(sha256.New, r.key)

	mac.Write(source)

	return mac.Sum(r.b)
}
func (r *mac) HmacVerify(source, signature []byte) bool {
	return hmac.Equal(r.Hmac(source), signature)
}

// Poly1305
// key *[32]byte key2
// b
func (r *mac) Poly1305(source []byte) []byte {
	mac := poly1305.New(r.key2)

	_, err := mac.Write(source)
	if err != nil {
		panic(err)
	}

	return mac.Sum(r.b)
}
func (r *mac) Poly1305Verify(source, signature []byte) bool {
	mac := poly1305.New(r.key2)

	_, err := mac.Write(source)
	if err != nil {
		panic(err)
	}

	return mac.Verify(signature)
}
func (r *mac) Poly1305More(source []byte) [16]byte {
	var signature [16]byte

	poly1305.Sum(&signature, source, r.key2)

	return signature
}
func (r *mac) Poly1305MoreVerify(source []byte, signature [16]byte) bool {
	return poly1305.Verify(&signature, source, r.key2)
}

// Ecdsa
// ecdsaPrivateKey
func (r *mac) Ecdsa(source []byte) (*big.Int, *big.Int) {
	hash := sha256.Sum256(source)

	r1, s1, err := ecdsa.Sign(rand.Reader, r.ecdsaPrivateKey, hash[:])
	if err != nil {
		panic(err)
	}

	return r1, s1
}
func (r *mac) EcdsaVerify(source []byte, r1, s1 *big.Int) bool {
	hash := sha256.Sum256(source)

	return ecdsa.Verify(&r.ecdsaPrivateKey.PublicKey, hash[:], r1, s1)
}
func (r *mac) EcdsaASN1(source []byte) []byte {
	hash := sha256.Sum256(source)

	r1, err := ecdsa.SignASN1(rand.Reader, r.ecdsaPrivateKey, hash[:])
	if err != nil {
		panic(err)
	}

	return r1
}
func (r *mac) EcdsaASN1Verify(source []byte, r1 []byte) bool {
	hash := sha256.Sum256(source)

	return ecdsa.VerifyASN1(&r.ecdsaPrivateKey.PublicKey, hash[:], r1)
}

// Ed25519 非对称加密
// privateKey
// publicKey
func (r *mac) Ed25519(source []byte) []byte {
	return ed25519.Sign(r.privateKey, source)
}
func (r *mac) Ed25519Verify(source, signature []byte) bool {
	return ed25519.Verify(r.publicKey, source, signature)
}
